﻿using System;
using System.Collections.Generic;
using System.Text;
using net.veekee.common.reflection;
using net.veekee.logprocessor.plugin.output;
using net.veekee.common;
using net.veekee.logprocessor.plugin.input;
using net.veekee.common.designpattern;
using Oracle.DataAccess.Client;
using System.Data.Common;
using System.Data;

namespace net.veekee.logprocessor.plugin.gen.datasource
{
    public class OracleManager : DBConnection
    {
        private OracleConnection conn = null;
        private OracleTransaction currentTransaction = null;

        public override bool IsConnected
        {
            get
            {
                return (this.conn != null);
            }
        }

        public OracleManager()
        {
        }

        public override bool Connect(String cs)
        {
            try
            {
                if (this.IsConnected)
                {
                    Log.GetInstance().Warn("Oracle connection has already been connected... skipping");
                    return false;
                }
                if (cs == null)
                {
                    Log.GetInstance().Warn("Connection String is null... skipping");
                    return false;
                }
                Log.GetInstance().Info("Connecting to Oracle database");
                this.conn = new OracleConnection();
                this.conn.ConnectionString = cs;
                this.conn.Open();
                Log.GetInstance().Debug("Welcome on {0}/{1}", this.conn.HostName, this.conn.ServiceName);
                Log.GetInstance().Debug("Detected Oracle version: {0}", this.conn.ServerVersion);
                return true;
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("Error while connecting to Oracle database: {0}", e);
                this.conn = null;
            }
            return false;
        }

        public override void Disconnect()
        {
            try
            {
                if (!this.IsConnected)
                {
                    Log.GetInstance().Warn("Couldn't close connection: No Oracle connection available");
                    return;
                }
                
                if (this.currentTransaction != null)
                {
                    Log.GetInstance().Info("Terminating transaction from Oracle database");
                    this.currentTransaction.Dispose();
                }

                Log.GetInstance().Info("Disconnecting from Oracle database");
                this.conn.Close();
                this.conn.Dispose();
                this.conn = null;
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("Error while disconnecting from Oracle database: {0}", e);
                this.conn = null;
            }
        }

        public override int Execute(String sql, Action<DbDataReader> action)
        {
            OracleCommand cmd = null;
            DbDataReader reader = null;
            try
            {
                if (!this.IsConnected)
                {
                    Log.GetInstance().Warn("Couldn't execute query: No Oracle connection available");
                    return -1; 
                }
                Log.GetInstance().Trace("Executing SQL: {0}", sql);

                cmd = new OracleCommand(sql);
                cmd.Connection = this.conn;
                cmd.CommandType = CommandType.Text;

                reader = cmd.ExecuteReader();

                int rows = 0;
                while (reader.Read())
                {
                    rows++;
                    action(reader);
                }
                return rows;
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("Error while executing SQL: {0}", e);
                return -1;
            }
            finally
            {
                if (reader != null) reader.Close();
                if (cmd != null) cmd.Dispose();
            }
        }

        public override int ExecuteNonQuery(String sql)
        {
            OracleCommand cmd = null;
            try
            {
                if (!this.IsConnected)
                {
                    Log.GetInstance().Warn("Couldn't execute query: No Oracle connection available");
                    return -1;
                }
                Log.GetInstance().Trace("Executing SQL: {0}", sql);

                cmd = new OracleCommand(sql);
                cmd.Connection = this.conn;
                cmd.CommandType = CommandType.Text;
                if (this.currentTransaction != null)
                    cmd.Transaction = this.currentTransaction;

                return cmd.ExecuteNonQuery();
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("Error while executing SQL: {0}", e);
                return -1;
            }
            finally
            {
                if (cmd != null) cmd.Dispose();
            }
        }

        public override void BeginTransaction()
        {
            try
            {
                if (!this.IsConnected)
                {
                    Log.GetInstance().Warn("Couldn't start transaction: No Oracle connection available");
                    return;
                }
                if (this.currentTransaction != null)
                {
                    Log.GetInstance().Warn("Couldn't start transaction: A transaction is currently opened");
                    return;
                }
                Log.GetInstance().Trace("Beginning transaction");
                this.currentTransaction = this.conn.BeginTransaction();
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("Error while beginning transaction: {0}", e);
                this.currentTransaction = null;
            }
        }

        public override void EndTransaction(bool autocommit = true)
        {
            try
            {
                if (!this.IsConnected)
                {
                    Log.GetInstance().Warn("Couldn't end transaction: No Oracle connection available");
                    return;
                }
                if (this.currentTransaction == null)
                {
                    Log.GetInstance().Warn("Couldn't end transaction: No transaction opened");
                    return;
                }
                Log.GetInstance().Trace("Ending transaction");
                if (autocommit)
                {
                    Log.GetInstance().Trace("Auto commiting");
                    this.currentTransaction.Commit();
                }
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("Error while ending transaction: {0}", e);
            }
            finally
            {
                if (this.currentTransaction != null) this.currentTransaction.Dispose();
            }
            this.currentTransaction = null;
        }

        public override void Commit()
        {
            try
            {
                if (!this.IsConnected)
                {
                    Log.GetInstance().Warn("Couldn't commit transaction: No Oracle connection available");
                    return;
                }
                if (this.currentTransaction == null)
                {
                    Log.GetInstance().Warn("Couldn't commit transaction: No transaction opened");
                    return;
                }
                Log.GetInstance().Trace("Commiting");
                this.currentTransaction.Commit();
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("Error while commiting transaction: {0}", e);
            }
        }

        public override void Rollback()
        {
            try
            {
                if (!this.IsConnected)
                {
                    Log.GetInstance().Warn("Couldn't rollback transaction: No Oracle connection available");
                    return;
                }
                if (this.currentTransaction == null)
                {
                    Log.GetInstance().Warn("Couldn't rollback transaction: No transaction opened");
                    return;
                }
                Log.GetInstance().Trace("Rollbacking");
                this.currentTransaction.Rollback();
            }
            catch (Exception e)
            {
                Log.GetInstance().Error("Error while rollbacking transaction: {0}", e);
            }
        }
    }
}
